package com.polidea.rxohosble2.internal.util;

import bleshadow.javax.inject.Inject;
import com.polidea.rxohosble2.exceptions.BleException;
import com.polidea.rxohosble2.internal.RxBleLog;
import com.polidea.rxohosble2.scan.ScanResult;
import com.polidea.rxohosble2.annotation.Nullable;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.app.Context;
import ohos.bluetooth.BluetoothHost;
import ohos.bluetooth.BluetoothRemoteDevice;
import ohos.bluetooth.ble.*;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.rpc.RemoteException;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

public class RxBleAdapterWrapper {

    public static class LeScanSetting {
        public int dutyRatio;
        public int matchingMode;
        public int time;

        public LeScanSetting(int dutyRatio, int matchingMode, int time) {
            this.dutyRatio = dutyRatio;
            this.matchingMode = matchingMode;
            this.time = time;
        }
    }

    public interface LeScanCallback {
        void onLeScan(BlePeripheralDevice device, int rssi, byte[] scanRecord);
    }

    public static abstract class ScanCallback implements BleCentralManagerCallback{
    }

    private BluetoothHost bluetoothHost = null;
    private BleCentralManager centralManager = null;
    private WeakReference<LeScanCallback> leScanCallback = null;
    private WeakReference<ScanCallback> scanCallback = null;
    private Intent callbackIntent = null;

    private static BleException nullBluetoothAdapter = new BleException("bluetoothAdapter is null");

    @Inject
    public RxBleAdapterWrapper(@Nullable Context context) {
        bluetoothHost = BluetoothHost.getDefaultHost(context);
        this.centralManager = new BleCentralManager(context, new BleCentralManagerCallback() {
            @Override
            public void scanResultEvent(BleScanResult bleScanResult) {
                if (leScanCallback != null && leScanCallback.get() != null) {
                    leScanCallback.get().onLeScan(bleScanResult.getPeripheralDevice(), bleScanResult.getRssi(), bleScanResult.getRawData());
                }
                if (scanCallback != null && scanCallback.get() != null) {
                    scanCallback.get().scanResultEvent(bleScanResult);
                }
                if (callbackIntent != null) {
                    ArrayList<String> list = new ArrayList<>();
                    list.add(bleScanResult.getPeripheralDevice().getDeviceAddr());
                    callbackIntent.setParam("EXTRA_LIST_SCAN_RESULT", list.toArray(new String[0]));
                    String[] result = callbackIntent.getStringArrayParam("EXTRA_LIST_SCAN_RESULT");
                    RxBleLog.i("sendEvent macAddr:"+result[0]);
                    sendEvent(callbackIntent);
                }
            }

            @Override
            public void scanFailedEvent(int i) {
                if (scanCallback != null && scanCallback.get() != null) {
                    scanCallback.get().scanFailedEvent(i);
                }
                if (callbackIntent != null) {
                    callbackIntent.setParam("EXTRA_ERROR_CODE", i);
                    sendEvent(callbackIntent);
                }
            }

            @Override
            public void groupScanResultsEvent(List<BleScanResult> list) {
                if (scanCallback != null && scanCallback.get() != null) {
                    scanCallback.get().groupScanResultsEvent(list);
                }
                if (callbackIntent != null) {
                    List<ScanResult> list2 = new ArrayList<>(list.size());
                    for(BleScanResult result : list) {
                        list2.add(new ScanResult(result));
                    }
                    callbackIntent.setParam("EXTRA_LIST_SCAN_RESULT", list2.toArray(new ScanResult []{}));
                    sendEvent(callbackIntent);
                }
            }
        });
    }

    private static void sendEvent(Intent intent) {
        try {
            Operation operation = new Intent.OperationBuilder()
                    .withAction("com.polidea.rxohosble2")
                    .build();
            intent.setOperation(operation);
            CommonEventData eventData = new CommonEventData(intent);
            CommonEventManager.publishCommonEvent(eventData);
        } catch (RemoteException e) {
            RxBleLog.e("Exception occurred during publishCommonEvent invocation.");
        }
    }

    public BluetoothRemoteDevice getRemoteDevice(String macAddress) {
        return bluetoothHost.getRemoteDev(macAddress);
    }

    public boolean hasBluetoothAdapter() {
        return centralManager != null;
    }


    public  boolean isBluetoothEnabled() {
        return getBluetoothState() == BluetoothHost.STATE_ON;
    }

    public  int getBluetoothState() {
        return bluetoothHost.getBtState();
    }

    @SuppressWarnings("deprecation")
    public boolean startLegacyLeScan(LeScanCallback leScanCallback) {

        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        this.leScanCallback = new WeakReference<>(leScanCallback);
        List<BleScanFilter> filters = new ArrayList<>();
        centralManager.startScan(filters);
        return true;
    }

    public void stopLegacyLeScan(LeScanCallback leScanCallback) {
        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        this.leScanCallback = null;
        centralManager.stopScan();
    }

    public void startLeScan(List<BleScanFilter> scanFilters, LeScanSetting scanSettings, ScanCallback scanCallback) {
        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        this.scanCallback = new WeakReference<>(scanCallback);
        if (scanSettings == null) {
            centralManager.startScan(scanFilters);
        } else {
            centralManager.startScan(scanFilters, scanSettings.dutyRatio, scanSettings.matchingMode, scanSettings.time);
        }
    }

    public int startLeScan(List<BleScanFilter> scanFilters, LeScanSetting scanSettings, Intent callbackIntent) {
        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        this.callbackIntent = callbackIntent;
        if (scanSettings == null) {
            centralManager.startScan(scanFilters);
        } else {
            centralManager.startScan(scanFilters, scanSettings.dutyRatio, scanSettings.matchingMode, scanSettings.time);
        }
        return 0;
    }

    public void stopLeScan(ScanCallback scanCallback) {
        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        this.scanCallback = null;
        centralManager.stopScan();
    }

    public void stopLeScan(Intent callbackIntent) {
        if (centralManager == null) {
            throw nullBluetoothAdapter;
        }
        centralManager.stopScan();
    }

    public List<BluetoothRemoteDevice> getBondedDevices() {
        return bluetoothHost.getPairedDevices();
    }
}
